---
sidebar_label: SSH
description: This is the API documentation for the OpenBao SSH secrets engine.
---

# SSH secrets engine (API)

This is the API documentation for the OpenBao SSH secrets engine. For general
information about the usage and operation of the SSH secrets engine, please see
the [SSH documentation](/docs/secrets/ssh).

This documentation assumes the SSH secrets engine is enabled at the `/ssh` path
in OpenBao. Since it is possible to enable secrets engines at any location, please
update your API calls accordingly.

## Create/Update role

This endpoint creates or updates a named role.

| Method | Path               |
| :----- | :----------------- |
| `POST` | `/ssh/roles/:name` |

### Parameters

- `name` `(string: <required>)` – Specifies the name of the role to create. This
  is part of the request URL.

- `default_user` `(string: "")` – Specifies the default username for which a
  credential will be generated. When the endpoint `creds/` is used without a
  username, this value will be used as default username. Its recommended to
  create individual roles for each username to ensure absolute isolation between
  usernames. This is required for OTP type roles.

  When `default_user_template` is set to `true`, this field can contain an identity
  template with any prefix or suffix, like `ssh-{{identity.entity.id}}-user`.

  For the CA type, if you wish this to be a valid principal, it must also be
  in `allowed_users`.

- `default_user_template` `(bool: false)` - If set, `default_users` can be specified
  using identity template values. A non-templated user is also permitted.

- `cidr_list` `(string: "")` – Specifies a comma separated list of CIDR blocks
  for which the role is applicable for. It is possible that a same set of CIDR
  blocks are part of multiple roles. This is a required parameter, unless the
  role is registered under the `/config/zeroaddress` endpoint. Note:
  [Not applicable for CA type]

- `exclude_cidr_list` `(string: "")` – Specifies a comma-separated list of CIDR
  blocks. IP addresses belonging to these blocks are not accepted by the role.
  This is particularly useful when big CIDR blocks are being used by the role
  and certain parts need to be kept out. Note:
  [Not applicable for CA type]

- `port` `(int: 22)` – Specifies the port number for SSH connection. Port number
  does not play any role in OTP generation. For the `otp` secrets engine type, this is
  just a way to inform the client about the port number to use. The port number
  will be returned to the client by OpenBao along with the OTP.

- `key_type` `(string: <required>)` – Specifies the type of credentials
  generated by this role. This can be either `otp` or `ca`.

- `allowed_users` `(string: "")` – If this option is not specified, or if it is
  `*`, the client can request a credential for any valid user at the remote
  host, including the admin user. To only allow an explicit list of users, set
  this parameter using a comma-separated username list to enforce it. When this
  parameter is set, the credentials are created only for `default_user` and
  usernames listed. Setting this option will enable all the users with access
  this role to fetch credentials for all other usernames in this list.
  When `allowed_users_template` is set to `true`, this field can contain an identity
  template with any prefix or suffix, like `ssh-{{identity.entity.id}}-user`.
  Use with caution. N.B.: if the type is `ca`, an empty list does not allow any user;
  instead you must use `*` to enable this behavior.

- `allowed_users_template` `(bool: false)` - If set, `allowed_users` can be specified
  using identity template policies. Non-templated users are also permitted.

- `allowed_domains` `(string: "")` – A comma-separated list of domains for which 
  a client can request a host certificate. If this option is explicitly set to
  `"*"`, then credentials can be created for any domain. See also
  `allow_bare_domains` and `allow_subdomains`.

- `allowed_domains_template` `(bool: false)` - If set, `allowed_domains` can be
  specified using identity template policies. Non-templated domains are also
  permitted.

- `ttl` `(string: "")` – Specifies the Time To Live value provided as a string
  duration with time suffix. Hour is the largest suffix. If not set, uses the
  system default value or the value of `max_ttl`, whichever is shorter.

- `max_ttl` `(string: "")` – Specifies the maximum Time To Live provided as a
  string duration with time suffix. Hour is the largest suffix. If not set,
  defaults to the system maximum lease TTL.

- `allowed_critical_options` `(string: "")` – Specifies a comma-separated list
  of critical options that certificates can have when signed. To allow any
  critical options, set this to an empty string. Will default to allowing any
  critical options.

- `allowed_extensions` `(string: "")` – Specifies a comma-separated list of
  extensions that certificates can have when signed. To allow a user to specify
  any extension, set this to `"*"`. If not set, users will not be allowed to
  specify extensions and will get the extensions specified within `default_extensions`.
  For the list of extensions, take a look at the [sshd
  manual's](https://man.openbsd.org/sshd#AUTHORIZED_KEYS_FILE_FORMAT)
  `AUTHORIZED_KEYS FILE FORMAT` section. You should add a `permit-` before the
  name of extension to allow it.

- `default_critical_options` `(map<string|string>: "")` – Specifies a map of
  critical options certificates should have if none are provided when signing.
  This field takes in key value pairs in JSON format. Note that these are not
  restricted by `allowed_critical_options`. Defaults to none.

- `default_extensions` `(map<string|string>: "")` – Specifies a map of
  extensions certificates should have if none are provided when signing. This
  field takes in key value pairs in JSON format. Note that these are not
  restricted by `allowed_extensions`. Defaults to none.

- `default_extensions_template` `(bool: false)` – If set, `default_extensions`
  can be specified using identity template policies. Non-templated extensions
  are also permitted.

- `allow_user_certificates` `(bool: false)` – Specifies if certificates are
  allowed to be signed for use as a 'user'.

- `allow_host_certificates` `(bool: false)` – Specifies if certificates are
  allowed to be signed for use as a 'host'.

- `allow_bare_domains` `(bool: false)` – Specifies if host certificates that are
  requested are allowed to use the base domains listed in `allowed_domains`, e.g.
  "example.com". This is a separate option as in some cases this can be
  considered a security threat.

- `allow_subdomains` `(bool: false)` – Specifies if host certificates that are
  requested are allowed to be subdomains of those listed in `allowed_domains`,
  e.g. if "example.com" is part of `allowed_domains`, this allows
  "foo.example.com".

- `allow_user_key_ids` `(bool: false)` – Specifies if users can override the key
  ID for a signed certificate with the "key_id" field. When false, the key ID
  will always be the token display name. The key ID is logged by the SSH server
  and can be useful for auditing.

- `key_id_format` `(string: "")` – When supplied, this value specifies a custom
  format for the key id of a signed certificate. The following variables are
  available for use: '\{\{token_display_name}}' - The display name of the token used
  to make the request. '\{\{role_name}}' - The name of the role signing the request.
  '\{\{public_key_hash}}' - A SHA256 checksum of the public key that is being signed.
  e.g. "custom-keyid-\{\{token_display_name}}"

- `allowed_user_key_lengths` `(map<string|(int|[]int|string)>: "")` – Specifies a
  map of ssh key types and their expected sizes which are allowed to be signed by
  the CA type. To specify multiple sizes, either use a comma-separated list or an
  array of allowed key widths. We support both OpenSSH-style key identifiers and
  short names (`rsa`, `ecdsa`, `dsa`, or `ed25519`) as keys. For example, a valid
  policy to allow common RSA and ECDSA key lengths might be:

  ```
  {
    "rsa": [2048, 3072, 4096],
    "ec": 256,
    "ecdsa-sha2-nistp521": 0
  }
  ```

  Note that when an algorithm identifier uniquely specifies a key length (such as
  with `ecdsa-sha2-nistp256` or `ed25519`), the value of the length is ignored (and
  can be zero).

:::warning

 **Note**: In FIPS 140-2 mode, the following algorithms are not certified
     and thus should not be used: `ed25519`.

:::

- `algorithm_signer` `(string: "default")` - Algorithm to sign keys with. Valid
  values are `ssh-rsa`, `rsa-sha2-256`, `rsa-sha2-512`, or `default`. This
  value may also be left blank to use the signer's default algorithm, and must
  be left blank or have value `default` for CA key types other than RSA.

:::warning

 **Note**: The value of `default` may change over time as vulnerabilities
  in algorithms are discovered. The present value for RSA keys is equivalent
  to `rsa-sha2-256`.

:::

:::warning

 **Warning**: The `algorithm_signer` value `ssh-rsa` uses the SHA-1 hash
  algorithm. This algorithm is now considered insecure and is not supported by
  current OpenSSH versions. As a result, OpenBao has made the new default
  `rsa-sha2-256` for RSA CA keys. It is strongly encouraged for all users to
  migrate to `rsa-sha2-256` or `default` if the role was created with an
  explicit `algorithm_signer=rsa-sha` parameter or has been migrated to such.

:::

- `not_before_duration` `(duration: "30s")` – Specifies the duration by which to
  backdate the `ValidAfter` property. Uses [duration format strings](/docs/concepts/duration-format).

- `allow_empty_principals` `(bool: false)` – If true, host and user
certificates can be issued without any valid principals. For host
certificates, this means that any domain a host claims to be will be trusted
by the connecting client. For user certificates, when a CA certificate is
placed in a user's AuthorizedKeys file, any principal on that certificate
will be allowed to connect. When `allowed_users` or `allowed_domains` is set
to `*` (corresponding to the role/certificate type),
`allow_empty_principals=false` still permits issuance.

### Sample payload

```json
{
  "key_type": "otp"
}
```

### Sample request

```shell-session
$ curl \
    --header "X-Vault-Token: ..." \
    --request POST \
    --data @payload.json \
    http://127.0.0.1:8200/v1/ssh/roles/my-role
```

## Read role

This endpoint queries a named role.

| Method | Path               |
| :----- | :----------------- |
| `GET`  | `/ssh/roles/:name` |

### Parameters

- `name` `(string: <required>)` – Specifies the name of the role to read. This
  is part of the request URL.

### Sample request

```shell-session
$ curl \
    --header "X-Vault-Token: ..." \
    http://127.0.0.1:8200/v1/ssh/roles/my-role
```

### Sample response

For an OTP role:

```json
{
  "cidr_list": "x.x.x.x/y",
  "default_user": "username",
  "key_type": "otp",
  "port": 22
}
```

For a CA role:

```json
{
  "allow_bare_domains": false,
  "allow_host_certificates": true,
  "allow_subdomains": false,
  "allow_user_key_ids": false,
  "allow_user_certificates": true,
  "allowed_critical_options": "",
  "allowed_extensions": "",
  "default_critical_options": {},
  "default_extensions": {},
  "max_ttl": "768h",
  "ttl": "4h"
}
```

## List roles

This endpoint returns a list of available roles. Only the role names are
returned, not any values.

| Method | Path         |
| :----- | :----------- |
| `LIST` | `/ssh/roles` |

### Parameters

 - `after` `(string: "")` - Optional entry to begin listing after for
   pagination; not required to exist.

 - `limit` `(int: 0)` - Optional number of entries to return; defaults
   to all entries.

### Sample request

```shell-session
$ curl \
    --header "X-Vault-Token: ..." \
    --request LIST \
    http://127.0.0.1:8200/v1/ssh/roles
```

### Sample response

```json
{
  "auth": null,
  "data": {
    "keys": ["dev", "prod"],
    "key_info": {
      "dev": {
        "key_type": "ca"
      }
    }
  },
  "lease_duration": 2764800,
  "lease_id": "",
  "renewable": false
}
```

## Delete role

This endpoint deletes a named role.

| Method   | Path               |
| :------- | :----------------- |
| `DELETE` | `/ssh/roles/:name` |

### Parameters

- `name` `(string: <required>)` – Specifies the name of the role to delete. This
  is part of the request URL.

### Sample request

```shell-session
$ curl \
    --header "X-Vault-Token: ..." \
    --request DELETE \
    --data @payload.json \
    http://127.0.0.1:8200/v1/ssh/roles/my-role
```

## List Zero-Address roles

This endpoint returns the list of configured zero-address roles.

| Method | Path                      |
| :----- | :------------------------ |
| `GET`  | `/ssh/config/zeroaddress` |

### Sample request

```shell-session
$ curl \
    --header "X-Vault-Token: ..." \
    http://127.0.0.1:8200/v1/ssh/config/zeroaddress
```

### Sample response

```json
{
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "roles": ["otp_key_role"]
  },
  "warnings": null,
  "auth": null
}
```

## Configure Zero-Address roles

This endpoint configures zero-address roles.

| Method | Path                      |
| :----- | :------------------------ |
| `POST` | `/ssh/config/zeroaddress` |

### Parameters

- `roles` `(string: <required>)` – Specifies a string containing comma separated
  list of role names which allows credentials to be requested for any IP
  address. CIDR blocks previously registered under these roles will be ignored.

### Sample payload

```json
{
  "roles": ["otp_key_role"]
}
```

### Sample request

```shell-session
$ curl \
    --header "X-Vault-Token: ..." \
    --request POST \
    --data @payload.json \
    http://127.0.0.1:8200/v1/ssh/config/zeroaddress
```

## Delete Zero-Address role

This endpoint deletes the zero-address roles configuration.

| Method   | Path                      |
| :------- | :------------------------ |
| `DELETE` | `/ssh/config/zeroaddress` |

### Sample request

```shell-session
$ curl \
    --header "X-Vault-Token: ..." \
    --request DELETE \
    http://127.0.0.1:8200/v1/ssh/config/zeroaddress
```

## Generate SSH credentials

This endpoint creates credentials for a specific username and IP with the
parameters defined in the given role.

| Method | Path               |
| :----- | :----------------- |
| `POST` | `/ssh/creds/:name` |

### Parameters

- `name` `(string: <required>)` – Specifies the name of the role to create
  credentials against. This is part of the request URL.

- `username` `(string: "")` – Specifies the username on the remote host.

- `ip` `(string: <required>)` – Specifies the IP of the remote host.

### Sample payload

```json
{
  "ip": "1.2.3.4"
}
```

### Sample request

```shell-session
$ curl \
    --header "X-Vault-Token: ..." \
    --request POST \
    --data @payload.json \
    http://127.0.0.1:8200/v1/ssh/creds/my-role
```

### Sample response

For an OTP role:

```json
{
  "lease_id": "sshs/creds/c3c2e60c-5a48-415a-9d5a-a41e0e6cdec5/3ee6ad28-383f-d482-2427-70498eba4d96",
  "renewable": false,
  "lease_duration": 2764800,
  "data": {
    "ip": "127.0.0.1",
    "key": "6d6411fd-f622-ea0a-7e2c-989a745cbbb2",
    "key_type": "otp",
    "port": 22,
    "username": "rajanadar"
  },
  "warnings": null,
  "auth": null
}
```

## List roles by IP

This endpoint lists all of the roles with which the given IP is associated.

| Method | Path          |
| :----- | :------------ |
| `POST` | `/ssh/lookup` |

### Parameters

- `ip` `(string: <required>)` – Specifies the IP of the remote host.

### Sample payload

```json
{
  "ip": "1.2.3.4"
}
```

### Sample request

```shell-session
$ curl \
    --header "X-Vault-Token: ..." \
    --request POST \
    --data @payload.json \
    http://127.0.0.1:8200/v1/ssh/lookup
```

### Sample response

An array of roles as a secret structure.

```json
{
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "roles": [
      "fe6f61b7-7e4a-46a6-b2c8-0d530b8513df",
      "6d6411fd-f622-ea0a-7e2c-989a745cbbb2"
    ]
  },
  "warnings": null,
  "auth": null
}
```

## Verify SSH OTP

This endpoint verifies if the given OTP is valid. This is an unauthenticated
endpoint.

| Method | Path          |
| :----- | :------------ |
| `POST` | `/ssh/verify` |

### Parameters

- `otp` `(string: <required>)` – Specifies the One-Time-Key that needs to be
  validated.

### Sample payload

```json
{
  "otp": "bad2b3-..."
}
```

### Sample request

```shell-session
$ curl \
    --header "X-Vault-Token: ..." \
    --request POST \
    --data @payload.json \
    http://127.0.0.1:8200/v1/ssh/verify
```

### Sample response

```json
{
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "ip": "127.0.0.1",
    "username": "rajanadar"
  },
  "warnings": null,
  "auth": null
}
```

## Submit CA information

This endpoint allows submitting the CA information for the secrets engine via an SSH
key pair. _If you have already set a certificate and key, they will be
overridden._

| Method | Path             | Content-Type               |
| :----- | :--------------- | -------------------------- |
| `POST` | `/ssh/config/ca` | `200/204 application/json` |

### Parameters

- `private_key` `(string: "")` – Specifies the private key part the SSH CA key
  pair; required if `generate_signing_key` is false.

- `public_key` `(string: "")` – Specifies the public key part of the SSH CA key
  pair; required if `generate_signing_key` is false.

- `generate_signing_key` `(bool: true)` – Specifies if OpenBao should generate
  the signing key pair internally. If `true`, an RSA key pair is generated, and
  the generated public key is returned so you can add it to your configuration.
  If `false`, then you must provide `private_key` and `public_key`, but these
  can be of any valid signing key type.

- `key_type` `(string: ssh-rsa)` - Specifies the desired key type for the
  generated SSH CA key when `generate_signing_key` is set to `true`. Valid
  values are OpenSSH key type identifiers (`ssh-rsa`, `ecdsa-sha2-nistp256`,
  `ecdsa-sha2-nistp384`, `ecdsa-sha2-nistp521`, or `ssh-ed25519`) or an
  algorithm (`rsa`, `ec`, or `ed25519`).

:::warning

 **Note**: In FIPS 140-2 mode, the following algorithms are not certified
      and thus should not be used: `ed25519`.

:::

- `key_bits` `(int: 0)` - Specifies the desired key bits for the generated SSH
  CA key when `generate_signing_key` is set to `true`. This is only used for
  variable length keys (such as `ssh-rsa`, where the value of `key_bits`
  specifies the size of the RSA key pair to generate; with the default `0`
  value resulting in a 4096-bit key) or when the `ec` algorithm is specified
  in `key_type` (where the value of `key_bits` identifies which NIST P-curve
  to use; `256`, `384`, or `521`, with the default `0` value resulting in a
  NIST P-256 key).

### Sample payload

```json
{
  "generate_signing_key": true
}
```

### Sample request

```shell-session
$ curl \
    --header "X-Vault-Token: ..." \
    --request POST \
    --data @payload.json \
    http://127.0.0.1:8200/v1/ssh/config/ca
```

### Sample response

This will return a `204` response if `generate_signing_key` was unset or false.

This will return a `200` response if `generate_signing_key` was true:

```json
{
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "public_key": "ssh-rsa AAAAHHNzaC1y...\n"
  },
  "warnings": null
}
```

## Delete CA information

This endpoint deletes the CA information for the backend via an SSH key pair.

| Method   | Path             |
| :------- | :--------------- |
| `DELETE` | `/ssh/config/ca` |

### Sample request

```shell-session
$ curl \
    --header "X-Vault-Token: ..." \
    --request DELETE \
    http://127.0.0.1:8200/v1/ssh/config/ca
```

## Read public key (Unauthenticated)

This endpoint returns the configured/generated public key. This is an unauthenticated
endpoint.

:::warning

Note: this is a raw response endpoint without JSON encoding; use
   `openbao read -format=raw` or an external tool (e.g., `curl`) to fetch this
   value.

:::

| Method | Path              | Content-Type     |
| :----- | :---------------- | ---------------- |
| `GET`  | `/ssh/public_key` | `200 text/plain` |

### Sample request

```shell-session
$ curl http://127.0.0.1:8200/v1/ssh/public_key
```

### Sample response

```text
    ssh-rsa AAAAHHNzaC1y...
```

## Read public key (Authenticated)

This endpoint reads the configured/generated public key.

| Method | Path             |
| :----- | :--------------- |
| `GET`  | `/ssh/config/ca` |

### Sample request

```shell-session
$ curl \
    --header "X-Vault-Token: ..." \
    http://127.0.0.1:8200/v1/ssh/config/ca
```

### Sample response

```json
{
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "public_key": "ssh-rsa AAAAHHNzaC1y...\n"
  },
  "warnings": null
}
```

## Sign SSH key

This endpoint signs an SSH public key based on the supplied parameters and 
subject to the restrictions of the role named in the path. Both `create` and 
`update` policy capabilities are needed to sign and update SSH keys. If only 
`create` capability is granted, and a SSH key does not exist, it will be created 
using the default parameters already configured. If only `update` capability is 
available and a SSH key does not exist, an error will be returned and SSH keys 
must exist already before may be updated.

It is similar to the endpoint `/ssh/issue/:name`. Instead of issuing new
SSH credentials, this returns a certificate for the given SSH public key.

The issued certificate uses the defaults specified in the role named in
this endpoint. Where not restricted by the parameters of this role, the
parameters of the issued certificate can be further customized in this API call.

:::warning

**Note**: The issued certificate is returned but _not_ stored by OpenBao.
   If you do not save it from the response, request it again by repeating
   this request.

:::

| Method | Path              |
| :----- | :---------------- |
| `POST` | `/ssh/sign/:name` |

### Parameters

- `name` `(string: <required>)` – Specifies the name of the role to sign. This
  is part of the request URL.

- `public_key` `(string: <required>)` – Specifies the SSH public key that should
  be signed.

- `ttl` `(string: "")` – Specifies the Requested Time To Live. Cannot be greater
  than the role's `max_ttl` value. If not provided, the role's `ttl` value will
  be used. Note that the role values default to system values if not explicitly
  set.

- `valid_principals` `(string: "")` – Specifies valid principals, either
  usernames or hostnames, that the certificate should be signed for.

- `cert_type` `(string: "user")` – Specifies the type of certificate to be
  created; either "user" or "host".

- `key_id` `(string: "")` – Specifies the key id that the created certificate
  should have. If not specified, the display name of the token will be used.

- `critical_options` `(map<string|string>: "")` – Specifies a map of the
  critical options that the certificate should be signed for. Defaults to none.

- `extensions` `(map<string|string>: "")` – Specifies a map of the extensions
  that the certificate should be signed for. Defaults to none.

### Sample payload

```json
{
  "public_key": "ssh-rsa ..."
}
```

### Sample request

```shell-session
$ curl \
    --header "X-Vault-Token: ..." \
    --request POST \
    --data @payload.json \
    http://127.0.0.1:8200/v1/ssh/sign/my-key
```

### Sample response

```json
{
  "lease_id": "ssh/sign/example/097bf207-96dd-0041-0e83-b23bd1923993",
  "renewable": false,
  "lease_duration": 21600,
  "data": {
    "serial_number": "f65ed2fd21443d5c",
    "signed_key": "ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1y...\n"
  },
  "auth": null
}
```

## Generate certificate and key

This endpoint issues a new set of SSH credentials (private key and certificate).

It is similar to the endpoint `/ssh/sign/:name`: Instead of signing an existing
SSH public key, it generates and issues new SSH credentials (key and certificate).

The issued certificate uses the defaults specified in the role named in
this endpoint. Where not restricted by the parameters of this role, the
parameters of the issued certificate can be further customized in this API call.

:::warning

**Note**: The issued credentials are returned but _not_ stored by OpenBao.
   If you do not save them from the response, issue new credentials by using
   this request again.

:::

| Method | Path               |
| :----- | :----------------  |
| `POST` | `/ssh/issue/:name` |

### Parameters

- `name` `(string: <required>)` – Specifies the name of the role to create the
  certificate against. This is part of the request URL.

- `key_type` `(string: "rsa")` – Specifies the desired key type; must be `rsa`, `ed25519`
  or `ec`.

- `key_bits` `(int: 0)` – Specifies the number of bits to use for the
  generated keys. Allowed values are 0 (universal default); with
  `key_type=rsa`, allowed values are: 2048 (default), 3072, or
  4096; with `key_type=ec`, allowed values are: 256 (default), 384,
  or 521; ignored with `key_type=ed25519`.

- `ttl` `(string: "")` – Specifies the Requested Time To Live. Cannot be greater
  than the role's `max_ttl` value. If not provided, the role's `ttl` value will
  be used. Note that the role values default to system values if not explicitly
  set.

- `valid_principals` `(string: "")` – Specifies valid principals, either
  usernames or hostnames, that the certificate should be signed for.

- `cert_type` `(string: "user")` – Specifies the type of certificate to be
  created; either "user" or "host".

- `key_id` `(string: "")` – Specifies the key id that the created certificate
  should have. If not specified, the display name of the token will be used.

- `critical_options` `(map<string|string>: "")` – Specifies a map of the
  critical options that the certificate should be signed for. Defaults to none.

- `extensions` `(map<string|string>: "")` – Specifies a map of the extensions
  that the certificate should be signed for. Defaults to none.

### Sample payload

```json
{
  "key_type": "rsa",
  "key_bits":  2048
}
```

### Sample request

```shell-session
$ curl \
    --header "X-Vault-Token: ..." \
    --request POST \
    --data @payload.json \
    http://127.0.0.1:8200/v1/ssh/issue/my-role
```

### Sample response

```json
{
  "request_id": "94fd1102-08a1-c207-0e3e-657e8f80c09e",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "serial_number": "1e965817eb12a511",
    "signed_key": "ssh-rsa-cert-v01@openssh.com AAAAHHN...\n",
    "private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAwer03vkQrPV+wWpbisJJv2CKqHmMz+Ej0ctLbhpOmR2CY9S9\n...\nQN351pgTphi6nlCkGPzkDuwvtxSxiCWXQcaxrHAL7MiJpPzkIBq1\n-----END RSA PRIVATE KEY-----\n",
    "private_key_type": "rsa"
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}
```

## Tidy host keys

This endpoint removes all existing host keys from OpenBao, if any are present.
These keys were used with the Dynamic Keys functionality, which were removed
from this engine.

:::warning

Note: This does not clean up any pending dynamic key leases and will not
   remove these keys from systems with authorized hosts entries created by
   OpenBao. That must be done manually by an operator, potentially before the
   removal of these host keys if they are necessary to access these
   systems.

:::

| Method   | Path                     |
| :------- | :----------------------- |
| `DELETE` | `/ssh/tidy/dynamic-keys` |

### Sample request

```shell-session
$ curl \
    --header "X-Vault-Token: ..." \
    --request DELETE \
    http://127.0.0.1:8200/v1/ssh/issue/my-role
```

### Sample response

```json
{
  "request_id": "",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "message": "Removed 15 of 15 host keys."
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}
```
